-------------------------------------------------------------------------------
--
-- CAN Controller Package
--  
-- Part of CAN Controller project
--  
-- Author(s):
--   Guy Eschemann, guy@noasic.com
--  
-------------------------------------------------------------------------------
--
-- Copyright (c) 2022 Guy Eschemann
-- 
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
-- 
--     http://www.apache.org/licenses/LICENSE-2.0
-- 
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use work.can_pkg.all;

package can_controller_pkg is

    -- Error states
    constant ERROR_ACTIVE  : unsigned(1 downto 0) := unsigned'("00");
    constant ERROR_PASSIVE : unsigned(1 downto 0) := unsigned'("01");
    constant BUS_OFF       : unsigned(1 downto 0) := unsigned'("10");

    -- Test modes
    constant NORMAL_OPERATION : unsigned(1 downto 0) := unsigned'("00");
    constant LISTEN_ONLY      : unsigned(1 downto 0) := unsigned'("01");
    constant LOOPBACK         : unsigned(1 downto 0) := unsigned'("10");

    -- CAN Controller configuration structure
    type t_can_controller_config is record
        prescaler : unsigned(7 downto 0); -- Bitrate prescaler. Sets the length of a time quantum (TQ) in system clock cycles.
        tseg1     : unsigned(3 downto 0); -- Time segment 1. Length of the first time segment in time quantums.
        tseg2     : unsigned(2 downto 0); -- Time segment 1. Length of the second time segment in time quantums.
        sjw       : unsigned(1 downto 0); -- Synchronization jump width
        testmode  : unsigned(1 downto 0); -- Test mode (0: normal operation, 1: listen-only mode, 2: loopback mode)                
    end record t_can_controller_config;

    -- CAN Controller status structure
    type t_can_controller_status is record
        error_state    : unsigned(1 downto 0); -- The CAN controller's error state (0: error active, 1: error passive, 2: bus off)
        rx_error_count : unsigned(7 downto 0); -- The receive error counter
        tx_error_count : unsigned(8 downto 0); -- The transmit error counter
    end record t_can_controller_status;

    -- CAN Controller interrupt structure
    type t_can_controller_interrupt is record
        bit_error   : std_logic;        -- Bit error
        stuff_error : std_logic;        -- Stuffing error
        crc_error   : std_logic;        -- CRC error
        form_error  : std_logic;        -- Form error
        ack_error   : std_logic;        -- Unacknowledged message
        arb_loss    : std_logic;        -- Arbitration lost while sending a message
        overload    : std_logic;        -- Received an overload frame
    end record t_can_controller_interrupt;

    type t_can_controller_debug is record
        bsp_can_field      : t_can_field; -- the currently transmitted/received CAN message field 
        bsp_can_field_slv  : std_logic_vector(4 downto 0); -- std_logic_vector version of 'bsp_can_field' 
        bsp_transmitting   : std_logic; -- signals that the CAN controller is currently transmitting
        bsp_receiving      : std_logic; -- signals that the CAN controller is currently receiving
        bsp_stuff_bit      : std_logic; -- signals that the current transmitted/received bit is a stuff bit
        bsp_bit_idx_u5     : std_logic_vector(4 downto 0); -- index of the current bit within the current field (unsigned integer)
        bsp_byte_idx_u3    : std_logic_vector(2 downto 0); -- index of the current data field byte (unsigned integer)
        btl_tx_clk         : std_logic; -- the transmission clock-enable
        btl_rx_clk         : std_logic; -- the reception clock-enable
        btl_resync         : std_logic; -- signals a resynchronization event
        btl_phase_error_s6 : std_logic_vector(5 downto 0); -- the measured phase error (signed integer)
        btl_hard_sync      : std_logic; -- signals a hard synchronization event
        quant_clk          : std_logic; -- the quantum clock (generated by the prescaler)
        can_rx             : std_logic; -- current level at the controller's CAN RX input
        can_tx             : std_logic; -- current level at the controller's CAN TX output
    end record;

    -- Data frame fields
    type t_can_data_frame_field is (NONE, START_OF_FRAME, ARBITRATION, CONTROL, DATA, CRC, ACK_SLOT, ACK_DELIMITER, END_OF_FRAME);

    -- Returns true if one or more interrupt bits are set
    function interrupt_occurred(interrupts : t_can_controller_interrupt) return boolean;

end package can_controller_pkg;

package body can_controller_pkg is
    function interrupt_occurred(interrupts : t_can_controller_interrupt) return boolean is
    begin
        if interrupts.bit_error = '1' then
            return true;
        end if;
        if interrupts.stuff_error = '1' then
            return true;
        end if;
        if interrupts.crc_error = '1' then
            return true;
        end if;
        if interrupts.form_error = '1' then
            return true;
        end if;
        if interrupts.ack_error = '1' then
            return true;
        end if;
        if interrupts.arb_loss = '1' then
            return true;
        end if;
        if interrupts.overload = '1' then
            return true;
        end if;
        return false;
    end function;

end package body can_controller_pkg;
